package com.basketball.gym.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.basketball.gym.mapper.InformationMapper;
import com.basketball.gym.mapper.WalletMapper;
import com.basketball.gym.pojo.*;
import com.basketball.gym.pojo.state.RoleId;
import com.basketball.gym.utils.*;
import com.basketball.gym.mapper.UserMapper;
import com.basketball.gym.pojo.state.RedisHeader;
import com.basketball.gym.pojo.state.ResponseState;
import com.basketball.gym.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 赵肖云
 * @since 2021-03-15
 */
@Validated
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Autowired
    private AliYunService aliYunService;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private WXService wxService;
    @Autowired
    private Logger logger;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private RedisTemplate<String, Role> roleRedisTemplate;
    @Autowired
    private JwtService jwtService;
    @Autowired
    private InformationMapper informationMapper;
    @Autowired
    private WalletMapper walletMapper;

    /**
     * 登录
     *
     * @param code ：code
     * @return user
     */
    @Transactional
    @Override
    public ResponseData<User> login(@NotNull(message = "code不能为空") String code) {
        try {
            Map<String, Object> data = wxService.getMiNiOpenId(code);
            String openId = (String) data.get("openid");
            if (openId == null) {
                switch ((int) data.get("errcode")) {
                    case -1:
                        return new ResponseData<>("系统繁忙，请稍候再试", -1);
                    case 40029:
                        return new ResponseData<>("code无效", 40029);
                    case 45011:
                        return new ResponseData<>("请求频率过高", 45011);
                    case 40163:
                        return new ResponseData<>("code已经被使用", 40163);
                    default:
                        return new ResponseData<>(ResponseState.ERROR.getMessage(), ResponseState.ERROR.getValue());
                }
            }
            QueryWrapper<User> openidWrapper = new QueryWrapper<>();
            openidWrapper.eq("open_id", openId);
            User user = userMapper.selectOne(openidWrapper);
            //判断该用户是否已经注册
            if (user == null) {
                user = new User(openId);
                userMapper.insert(user);
                //插入用户角色
//                userMapper.insertRole(user.getId(), RoleId.USER.getValue());
                user.setState(1);
                Wallet wallet = new Wallet();
                wallet.setUserId(user.getId());
                walletMapper.insert(wallet);
            }
            if (user.getState() != 1) {
                return new ResponseData<>(ResponseState.ACCOUNT_IS_ILLEGAL.getMessage(), ResponseState.ACCOUNT_IS_ILLEGAL.getValue());
            }
            //储存用户角色
            roleRedisTemplate.delete(RedisHeader.ROLE.getHeader() + user.getId());
//            roleRedisTemplate.opsForList().rightPushAll(RedisHeader.ROLE.getHeader()+user.getId(), user.getRoles());
            //储存session_key
            String sessionKey = (String) data.get("session_key");
            stringRedisTemplate.opsForValue().set(RedisHeader.SESSION_KEY.getHeader() + user.getId(), sessionKey);
            //生成、储存token
            String token = jwtService.getAccessToken(user.getId(), "user");
            stringRedisTemplate.opsForValue().set(RedisHeader.TOKEN.getHeader() + user.getId(), token);
            //生成、储存refreshToken
            String refreshToken = jwtService.getRefreshToken(user.getId(), "user");
            stringRedisTemplate.opsForValue().set(RedisHeader.REFRESH_TOKEN.getHeader() + user.getId(), refreshToken);
            return new ResponseData<>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue(), token, refreshToken, user);
        } catch (Exception e) {
            logger.error("操作失败");
            logger.error(e.getMessage());
            return new ResponseData<>(ResponseState.ERROR.getMessage(), ResponseState.ERROR.getValue());
        }
    }


    /**
     * 将从微信获取的用户信息更新到数据库
     */
    @Override
    public ResponseData<User> updateInfo(@NotNull(message = "encryptedData不能为空") String encryptedData, @NotNull(message = "iv不能为空") String iv, User user) {
        String sessionKey = stringRedisTemplate.opsForValue().get(RedisHeader.SESSION_KEY.getHeader() + user.getId());
        user = userMapper.selectById(user.getId());
        if (user.getAvatarUrl() == null) {
            Map<String, Object> data = wxService.getUserInfo(encryptedData, sessionKey, iv);
            user.setWxInformation(data);
            userMapper.updateById(user);
            return new ResponseData<>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue(), user);
        } else {
            return new ResponseData<>(ResponseState.OPERATION_HAI_FINISH.getMessage(), ResponseState.OPERATION_HAI_FINISH.getValue());
        }
    }

    /**
     * 退出登录
     *
     * @param user：当前登录的用户
     * @return responseData
     */
    @Override
    public ResponseData<Object> logout(User user) {
        logger.info("id为{}的用户正在退出登录", user.getId());
        stringRedisTemplate.delete(RedisHeader.SESSION_KEY.getHeader() + user.getId());
        stringRedisTemplate.delete(RedisHeader.TOKEN.getHeader() + user.getId());
        stringRedisTemplate.delete(RedisHeader.REFRESH_TOKEN.getHeader() + user.getId());
        logger.info("退出成功");
        return new ResponseData<>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue());

    }

    /**
     * 更新Token
     *
     * @param refreshToken:refreshToken
     * @return token
     */
    @Override
    public ResponseData<Object> refresh(String refreshToken) {
        User user = (User) jwtService.getUser(refreshToken);
        if (user == null) {
            return new ResponseData<>(ResponseState.REFRESH_TOKEN_IS_ERROR.getMessage(), ResponseState.REFRESH_TOKEN_IS_EXPIRED.getValue());
        }
        String rightToken = stringRedisTemplate.opsForValue().get(RedisHeader.REFRESH_TOKEN.getHeader() + user.getId());
        System.out.println(rightToken);
        if (!refreshToken.equals(rightToken)) {
            return new ResponseData<>(ResponseState.REFRESH_TOKEN_IS_ERROR.getMessage(), ResponseState.REFRESH_TOKEN_IS_ERROR.getValue());
        }
        String newAccessToken = jwtService.getAccessToken(user.getId(), "user");
        String newRefreshToken = jwtService.getRefreshToken(user.getId(), "user");
        stringRedisTemplate.opsForValue().set(RedisHeader.TOKEN.getHeader() + user.getId(), newAccessToken);
        stringRedisTemplate.expire(RedisHeader.TOKEN.getHeader() + user.getId(), 2, TimeUnit.HOURS);
        stringRedisTemplate.opsForValue().set(RedisHeader.REFRESH_TOKEN.getHeader() + user.getId(), newRefreshToken);
        stringRedisTemplate.expire(RedisHeader.REFRESH_TOKEN.getHeader() + user.getId(), 15, TimeUnit.DAYS);
        return new ResponseData<Object>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue(), newAccessToken, newRefreshToken);
    }

    /**
     * 通过Id查询用户信息
     */
    @Override
    public ResponseData<User> getUser(User user) {
        user = userMapper.selectById(user.getId());
        user.setInformation(informationMapper.selectOne(WrapperUtils.getOneEqQueryWrapper("user_id", user.getId())));
        return new ResponseData<>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue(), user);
    }

    /**
     * 上传图片
     */
    @Override
    public ResponseData<Object> uploadPhoto(MultipartFile photo, User user) throws IOException {
        InputStream inputStream = photo.getInputStream();
        if (!FileUtils.isImage(inputStream)) {
            return new ResponseData<>(ResponseState.FILE_FORMAT_ERROR.getMessage(), ResponseState.FILE_FORMAT_ERROR.getValue());
        }
        photo.getOriginalFilename();
        String url = aliYunService.uploadFile(photo.getInputStream(), "user/" + user.getId() + "/" + StringUtils.getRandomString() + FileUtils.getFileSuffix(photo.getOriginalFilename()));
        return new ResponseData<>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue(), url);

    }

    /**
     * 更改头像
     */
    @Override
    public ResponseData<Object> updateAvatar(User user) {
        int result = userMapper.updateById(user);
        if (result == 1) {
            return new ResponseData<>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue());
        } else {
            return new ResponseData<>(ResponseState.USER_NOT_EXIST.getMessage(), ResponseState.USER_NOT_EXIST.getValue());
        }
    }

    /**
     * 绑定手机号时获取验证码
     */
    @Override
    public ResponseData<Object> getBindCode(String phone, User user) {
        user = userMapper.selectById(user.getId());
        if (user.getPhone() != null) {
            return new ResponseData<>(ResponseState.PHONE_HAS_BIND.getMessage(), ResponseState.PHONE_HAS_BIND.getValue());
        }
        String code=aliYunService.getBindPhoneCode(phone);
        if(code==null){
            return new ResponseData<>(ResponseState.ERROR.getMessage(),ResponseState.ERROR.getValue());
        }
        stringRedisTemplate.opsForValue().set(RedisHeader.PHONE_BIND_CODE.getHeader() + phone + user.getId(), code);
        stringRedisTemplate.expire(RedisHeader.PHONE_BIND_CODE.getHeader() + phone + user.getId(), 5, TimeUnit.MINUTES);
        return new ResponseData<>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue());
    }

    /**
     * 修改手机号时获取验证码
     */
    @Override
    public ResponseData<Object> getUpdateCode(String phone, User user) {
        user = userMapper.selectById(user.getId());
        String code=aliYunService.getUpdatePhoneCode(phone);
        if(code==null){
            return new ResponseData<>(ResponseState.ERROR.getMessage(),ResponseState.ERROR.getValue());
        }
        if (user.getPhone() == null) {
            return new ResponseData<>(ResponseState.PHONE_NOT_BIND.getMessage(), ResponseState.PHONE_NOT_BIND.getValue());
        }
        stringRedisTemplate.opsForValue().set(RedisHeader.PHONE_UPDATE_CODE.getHeader() + phone + user.getId(), code);
        stringRedisTemplate.expire(RedisHeader.PHONE_UPDATE_CODE.getHeader() + phone + user.getId(), 5, TimeUnit.MINUTES);
        return new ResponseData<>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue());

    }

    /**
     * 绑定/更改手机号时获取验证码
     */
    @Override
    public ResponseData<Object> bindPhone(@NotNull(message = "phone不能为空") @Pattern(regexp = "^[1]([3-9])[0-9]{9}$", message = "手机号格式错误") String phone, @NotNull(message = "code不能为空") String code, User user) {
        boolean isBind = true;
        user = userMapper.selectById(user.getId());
        String rightCode = null;
        if (user.getPhone() == null) {
            rightCode = stringRedisTemplate.opsForValue().get(RedisHeader.PHONE_BIND_CODE.getHeader() + phone + user.getId());
        } else {
            isBind = false;
            rightCode = stringRedisTemplate.opsForValue().get(RedisHeader.PHONE_UPDATE_CODE.getHeader() + phone + user.getId());
        }
        if (rightCode == null) {
            return new ResponseData<>(ResponseState.CODE_NOT_EXIST.getMessage(), ResponseState.CODE_NOT_EXIST.getValue());
        }
        if (!rightCode.equals(code)) {
            return new ResponseData<>(ResponseState.CODE_IS_ERROR.getMessage(), ResponseState.CODE_IS_ERROR.getValue());
        }
        user.setPhone(phone);
        int result = userMapper.updateById(user);
        if (result == 1) {
            if (isBind) {
                stringRedisTemplate.delete(RedisHeader.PHONE_BIND_CODE.getHeader() + phone + user.getId());
            } else {
                stringRedisTemplate.delete(RedisHeader.PHONE_UPDATE_CODE.getHeader() + phone + user.getId());
            }
            return new ResponseData<>(ResponseState.SUCCESS.getMessage(), ResponseState.SUCCESS.getValue());
        }

        return new ResponseData<>(ResponseState.USER_NOT_EXIST.getMessage(), ResponseState.USER_NOT_EXIST.getValue());
    }

}
